package study.mybatis.support.interceptor;

import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * 注册方式
 * （1）通过 Configuration 的 addInterceptor 方法
 * （2）通过 mybatis 全局配置文件标签 <plugin/>
 */
@Slf4j
@Intercepts({
        //@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class SqlCostInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 代理信息
        Object target = invocation.getTarget(); //目标对象
        Method method = invocation.getMethod(); //代理方法
        Object[] args = invocation.getArgs();   //方法参数

        //获取参数，if语句成立，表示sql语句有参数，参数格式是map形式
        Object parameter = null;
        if (args.length > 1) {
            parameter = args[1];
            //log.info("parameter={}", parameter.getClass().getName());
        }
        // MappedStatement
        MappedStatement mappedStatement = (MappedStatement) args[0];
        SqlCommandType sqlType = mappedStatement.getSqlCommandType();
        String sqlId = mappedStatement.getId();
        log.info("sql_type= {}, sql_id= {}", sqlType, sqlId);

        //（★）BoundSql就是封装mybatis最终产生的SQL类
//        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
//        log.info("parsing= {}", boundSql.getSql());
//        String mySql = boundSql.getSql() + " limit 2";
//        FieldUtils.setValue(boundSql, "parsing", mySql);
//        log.info("parsing= {}", boundSql.getSql());
        //（★）获取节点的配置
        Configuration configuration = mappedStatement.getConfiguration();

        //执行完上面的任务后，不改变原有的 sql 执行过程
        Object result;
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            result = invocation.proceed();
        } finally {
            log.info("{} cost time [{}] ms", sqlId, stopwatch.elapsed(TimeUnit.MILLISECONDS));
        }
        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}
